# -*- coding: utf-8 -*-
# created on 2016/12/28

from sympy import log, sympify, solve, Union, simplify, Symbol, S

from mathsolver.functions.base import (BaseFunction, BaseFunc, BaseEq, BaseSymbolValue, BaseIneq, BaseFuncName,
                                       BasePoly, BaseVariable, BaseFuncEq, BaseIneqs)
from mathsolver.functions.hanshu.dandiao_qiucan import QuJianDiZenQiuCan, QuJianDiJianQiuCan
from mathsolver.functions.hanshu.duicheng_jisuan import DuiChengZhongXing
from mathsolver.functions.hanshu.helper import check_func, get_rand_from_interval, check_inter
from mathsolver.functions.hanshu.zhiyu import ZhiYuDanDiaoXing
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSimplify
from mathsolver.functions.root.jiefangchen import JieFangChen


class HanShuInverse(BaseFunction):
    """
    函数y=\\frac{1+ln(x-1)}{2}(x>1)的反函数是()
        求函数的反函数
    或者
       求函数关于直线y=x对称的函数
    """

    def solver(self, *args):
        func = check_func(args[0])

        if isinstance(args[-1], (BaseIneq, BaseIneqs)):
            cond = check_inter(args[-1])
        else:
            cond = self.search(func.var)
            if cond is None:
                cond = S.Reals

        expression, symbol = func.expression, func.var
        target_symbol = Symbol("y")

        stepsolver = JieFangChen().solver(BaseEq([target_symbol, expression]), BaseVariable(symbol))
        solver_output = list(stepsolver.output[0].value[symbol])

        # 如果有多个解，需要讨论函数值域是否在定义域内部
        solver_output_length = len(solver_output)
        for so in solver_output:

            expression = simplify(so.subs({target_symbol: symbol}))
            # 如果含有 log, 调用 Mathematica 化简
            if expression.has(log):
                expression = MathematicaSimplify().solver(BasePoly(str(expression))).output[0].sympify()

            if len(args) > 1 and isinstance(args[1], BaseFuncName):
                funcname = args[1]
                answer = BaseFunc({"var": funcname.var, "name": funcname.name, "type": "", "expression": expression})
            else:
                answer = BaseFunc({"var": symbol, "name": "f", "type": "inverse", "expression": expression})

            interval = ZhiYuDanDiaoXing().solver(func, cond).output[0].value
            answer.dingyiyu = BaseSymbolValue({symbol: interval})

            if solver_output_length > 1:
                # 从 interval 里面随机选取一个值，代入函数表达式
                rand_val = get_rand_from_interval(interval)
                if answer.expression.subs(answer.var, rand_val) not in cond:
                    continue

            self.steps.append(["", "%s 的反函数为 %s" % (func.printing(), answer.printing())])
            self.output.append(answer)
            self.output.append(func)

        self.label.add("求函数的反函数")
        return self


def cunzai_fanhanshu(expr, qujian):
    """hs092.函数存在反函数的定义"""
    step = "函数在区间 %s 上存在反函数，即为 %s 在区间上具有单调性" % (qujian, expr)
    res = ((QuJianDiJianQiuCan, '单调递减'), (QuJianDiZenQiuCan, '单调递增'))
    return res, step


class CunZaiFanHanShuQiuCan(BaseFunction):
    """函数存在反函数求参数"""

    def solver(self, *args):
        func, qujian = check_func(args[0]), args[1]
        expr = func.expression

        # 函数存在反函数的定义
        dandiao_qiucan, step = cunzai_fanhanshu(expr, qujian.interval)
        res = []
        for dandiao_func, dandiao_text in dandiao_qiucan:
            try:
                dandiao_step = dandiao_func().solver(func, qujian)
                self.steps.append(["如果函数在区间上%s" % dandiao_text, ""])
                self.steps.extend(dandiao_step.steps)
                res.append(dandiao_step.output[0])
            except Exception:
                self.steps.append(["函数在区间上%s无意义" % dandiao_text, ""])

        canshu = res[0].value.keys()[0]
        fanwei = Union(item.value.values()[0] for item in res)
        res = BaseSymbolValue({canshu: fanwei})

        self.steps.append(["", "所以所求参数的范围为 %s" % res.printing()])
        self.output.append(res)
        self.label.add("函数存在反函数求参数")
        return self


class FanHanShuQiuZhi(BaseFunction):
    """利用反函数求函数的值"""

    def solver(self, *args):
        func, q_func = check_func(args[0]), args[1]
        expr, var = func.expression, func.var

        # 类型一
        if isinstance(q_func, BaseFuncName):
            # 利用反函数表示函数的值
            a = q_func.var
            res = solve(expr - a, var, dict=True)[0]
            res_format = "%s = %s" % (res.keys()[0], res.values()[0])
            self.steps.append(["由题意知 f(%s) = %s" % (var, a), "解得 %s" % res_format])
            self.steps.append(["所以 %s = %s" % (q_func.printing(), res_format), ""])
        # 类型二
        elif isinstance(q_func, BaseFuncEq):
            left, right = sympify(q_func.value)
            inner_func = left.args[0]
            res = solve(expr.subs(var, right) - inner_func, dict=True)[0]
            res_format = "%s = %s" % (res.keys()[0], res.values()[0])
            self.steps.append(["由题意知 f(%s) = %s" % (right, inner_func), "解得 %s" % res_format])
        else:
            raise ValueError('unknown type %s' % type(q_func))

        self.output.append(BaseSymbolValue(res))
        self.label.add("利用反函数求函数的值")
        return self


class FanHanShuQiuZhi2(BaseFunction):
    """利用反函数求函数的值2
    已知函数f(x)的反函数为g(x)=1+2lgx(x>0),则f(1)+g(1)=()
    :return BaseFunc, BaseFunc
    """

    def solver(self, *args):
        pass


def fanhanshu_duichengzhongxing(expr, point):
    """hs095.反函数的对称中心关系"""
    x, y = point
    res = (y, x)
    step = "f(x) = %s 的对称中心为 %s，则其反函数 y = f^{-1}(x) 的对称中心为 %s" % (expr, point, res)
    return res, step


class FanHanShuQiuDuiChengZhongXing(BaseFunction):
    """利用反函数求对称中心"""

    def solver(self, *args):
        func, point = check_func(args[0]), args[1].value
        expr = func.expression

        # 反函数的对称中心关系
        point, step = fanhanshu_duichengzhongxing(expr, point)
        self.steps.append(["", step])

        # 求函数对称中心
        step_solver = DuiChengZhongXing().solver(func)
        self.steps.extend(step_solver.steps)
        point2 = step_solver.output[0].value

        # 解方程
        eqs = [left - right for left, right in zip(point, point2)]
        res = solve(eqs, dict=True)[0]
        res_format = "%s = %s" % (res.keys()[0], res.values()[0])
        self.steps.append(["所以 %s = %s" % (point, point2), "解得 %s" % res_format])

        self.output.append(BaseSymbolValue(res))
        self.label.add("利用反函数求对称中心")
        return self


class FanHanShuZhiXianGuanXi(BaseFunction):
    """hs109.关于直线对称的单调函数互为反函数
       hs110.反函数关于直线对称"""

    def solver(self, *args):
        res = False
        if args[0] == "单调" and isinstance(args[1], BaseFuncName) \
                and isinstance(args[2], BaseFuncName) and args[4] == "反函数":
            res = True
        elif isinstance(args[0], BaseFuncName) and isinstance(args[1], BaseFuncName) \
                and args[2] == "反函数" and args[-1] == "对称":
            res = True

        self.output.append(BaseVariable(res))
        self.label.add("关于直线对称的单调函数互为反函数")
        return self


if __name__ == '__main__':
    pass
